/*  
  -- The Lime II Project -- 

  A tuplespaces-based middleware for coordinating agents and mobile hosts.
  Copyright (C) 2005.
  Gian Pietro Picco, Amy L. Murphy, Lorenzo Bellini.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

package lime2;
import java.util.*;

/**
 * Provides facilities for using queues of Objects.
 * 
 * @author Gian Pietro Picco
 * @author Amy Murphy
 * @author Lorenzo Bellini
 */

public class Queue implements java.io.Serializable 
{
 // internal structure for storage (please note that java.util.LinkedList is not internally synchronized)	
 private LinkedList list = new LinkedList();

 // methods are not only synchronized using the queue itself: we need also another object (.. wake up on empty queue) 
 private Object removalLock = new Object();

 /**
  * Removes the first item from the queue. If the queue is empty, then it waits for an item to remove.
  * 
  * @return Object
  */   
 public synchronized Object remove() 
 {
  while(list.size() == 0) 
  {
   try { wait(); } 
   catch(InterruptedException e) {}
  }
  Object item = list.removeFirst();
  if (list.size() == 0) synchronized(removalLock) { removalLock.notifyAll(); }
  return item;
 }

 /**
  * Adds an item to the end of the queue.
  *
  * @param item Object
  */
 public synchronized void add(Object item) 
 {
  list.addLast(item);
  notifyAll();
 }
 
 /**
  * Removes the first item from the queue, but it doesn't block if the queue is empty.
  * 
  * @return Object
  */
 public synchronized Object nonBlockingRemove() 
 {
  Object item = list.removeFirst();
  if (list.size() == 0) synchronized(removalLock) { removalLock.notifyAll(); }
  return item;
 }
 
 /**
  * Blocks until the queue is empty. 
  */
 public void waitUntilEmpty() 
 {
  synchronized(removalLock) 
  {
   if (list.size() != 0) try { removalLock.wait(); } catch(InterruptedException e) {}
  }
 }
 
 /**
  * Blocks until the queue is not empty. 
  */
 public synchronized void waitOnEmpty() 
 {
  if (list.size() == 0) try { wait(); } catch(InterruptedException e) {}
 }
 
 /**
  * Removes a specific item from the queue.
  * 
  * @param item to remove
  */
 public synchronized void removeElement (Object item) 
 {
  list.remove(item);
  if (list.size() == 0) synchronized(removalLock) { removalLock.notifyAll(); }
 }

 /**
  * Returns all the elements of the queue in the correct order.
  * 
  * @return Enumeration
  */
 public Object[] elements() { return list.toArray(); }

 /**
  * Tests whether the queue is empty.
  * 
  * @return <code>boolean</code>
  */
 public boolean isEmpty() { return list.size() == 0; }

 /**
  * Returns the size of the queue.
  * 
  * @return <code>int</code>
  */
 public int size() { return list.size(); }

}

